package core.rb;

import core.rb.r.Pol;
import core.rb.r.PR;
import core.sb.s.Seq;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.*;

/*Author: John Archer, Contact: john.archer.jpa@gmail.com*/
public class PB implements Serializable{
    private ArrayList <PR> prl;
    private Seq ref;
    private int qDist [];
    private int maxQ;

    public PB(Seq ref) {
        this.ref = ref;
        this.prl = new ArrayList();
    }
    
    public PB(Seq ref, ArrayList <PR> prl) {
        this.ref = ref;
        this.prl = prl;
    }

    public String getDNA(int n) {
        String read = "";
        String tBit = ref.getDNA().substring(this.getStart(n), (this.getEnd(n)>=ref.getDNA().length())? ref.getDNA().length() : this.getEnd(n) );
        char[] tchars = tBit.toCharArray();
        LinkedList <Character> rCon = new LinkedList();
        for (int x = 0; x < tchars.length; x++){rCon.add(new Character(tchars[x]));}
        ArrayList <Pol> polys = prl.get(n).getPols();
        int ins = 0;
        for (int p = 0; p < polys.size(); p++) {
            if (!polys.get(p).isIns()){rCon.set((polys.get(p).getTLoc() - prl.get(n).getStart() + ins), polys.get(p).getChar());}
            else{rCon.add((polys.get(p).getTLoc() - prl.get(n).getStart()) + (ins++), polys.get(p).getChar());}
        }
        for (int x = 0; x < rCon.size(); x++){read += rCon.get(x).charValue();}
        return read;
    }

    public String getDNA(int n, double t) {
        String read = "";
        String tBit = ref.getDNA().substring(this.getStart(n), (this.getEnd(n)>=ref.getDNA().length())? ref.getDNA().length() : this.getEnd(n));
        char[] tchars = tBit.toCharArray();
        LinkedList <Character> rCon = new LinkedList();
        for (int s = 0; s < tchars.length; s++){rCon.add(new Character(tchars[s]));}
        ArrayList <Pol> pols = prl.get(n).getPols();
        int ins = 0;
        for (int p = 0; p < pols.size(); p++) {
            if (pols.get(p).isIns() == false){
                if(pols.get(p).isDel() == true){rCon.set((pols.get(p).getTLoc() - prl.get(n).getStart() + ins), '-');}
                else{
                    if(pols.get(p).getPost() >= t){rCon.set((pols.get(p).getTLoc() - prl.get(n).getStart()  + ins), pols.get(p).getChar());}
                    else{rCon.set((pols.get(p).getTLoc() - prl.get(n).getStart() + ins), pols.get(p).getTChar());}
                }
            }
            else{rCon.add((pols.get(p).getTLoc() - prl.get(n).getStart()) + (ins++), pols.get(p).getChar());}
        }
        for (int x = 0; x < rCon.size(); x++){read += rCon.get(x).charValue();}
        return read;
    }

    public ArrayList <String> getDNA(int s, int e, double mt) {
        int sub = e - s;
        ArrayList <String>  theReads = new ArrayList <String>();
        boolean repeat = true;int lBand=0;
        while(repeat && lBand < this.getSize()){if(this.getRead(lBand++).getEnd() >= s){repeat = false;}}
        repeat = true;int uBand=lBand;
        while(repeat && uBand < this.getSize()){if(this.getRead(uBand++).getStart() >= e){repeat = false;}}
        int sCut,eCut;
        for(int r=lBand; r<uBand;r++){
            if(this.getRead(r).getStart() <= s && this.getRead(r).getEnd() >= e){
                sCut = s - this.getRead(r).getStart();
                eCut = sCut + sub;
                theReads.add(new String(this.getDNA(r, mt).substring(sCut, eCut).replace("-", "")));
            }
        }
        return theReads;
    }

    public String getScDNA(int n) {
        String tBit = ref.getDNA().substring(this.getStart(n), (this.getEnd(n)>=ref.getDNA().length())? ref.getDNA().length() : this.getEnd(n));
        char[] tchars = tBit.toCharArray();
        LinkedList <Character> rCon = new LinkedList();
        for (int s=0; s<tchars.length; s++){rCon.add(new Character(tchars[s]));}
        ArrayList <Pol> polys = prl.get(n).getPols();
        for (int p=0; p<polys.size(); p++){
            if(!polys.get(p).isIns()){rCon.set((polys.get(p).getTLoc() - prl.get(n).getStart()), polys.get(p).getChar());}
        }
        String read = "";
        for (int s = 0; s < rCon.size(); s++){read += rCon.get(s).charValue();}
        return read;
    }
    
    public ArrayList <String> getScDNA(int s, int e) {
        int sub = e - s;
        ArrayList <String>  prs = new ArrayList <String>();
        boolean repeat = true;int lBand=0;
        while(repeat && lBand < this.getSize()){if(this.getRead(lBand++).getEnd() >= s){repeat = false;}}
        repeat = true;int uBand=lBand;
        while(repeat && uBand < this.getSize()){if(this.getRead(uBand++).getStart() >= e){repeat = false;}}
        int sCut,eCut;
        for(int r=lBand; r<uBand;r++){
            if(this.getRead(r).getStart() <= s && this.getRead(r).getEnd() >= e){
                sCut = s - this.getRead(r).getStart();
                eCut = sCut + sub;
                prs.add(this.getScDNA(r).substring(sCut, eCut));
            }
        }
        return prs;
    }
    
    public String getScDNA(int n, double t) {
        String read = "";
        String tBit = ref.getDNA().substring(this.getStart(n), (this.getEnd(n)>=ref.getDNA().length())? ref.getDNA().length() : this.getEnd(n));
        char[] tchars = tBit.toCharArray();
        LinkedList <Character> rCon = new LinkedList();
        for (int s = 0; s < tchars.length; s++){rCon.add(new Character(tchars[s]));}
        ArrayList <Pol> polys = prl.get(n).getPols();
        for (int p = 0; p < polys.size(); p++) {
            if (polys.get(p).isIns() == false){
                if(polys.get(p).isDel() == true){rCon.set((polys.get(p).getTLoc() - prl.get(n).getStart()), '-');}
                else{
                    if(polys.get(p).getPost() >= t){rCon.set((polys.get(p).getTLoc() - prl.get(n).getStart()), polys.get(p).getChar());}
                    else{rCon.set((polys.get(p).getTLoc() - prl.get(n).getStart()), polys.get(p).getTChar());}
                }
            }
        }
        for (int x = 0; x < rCon.size(); x++){read += rCon.get(x).charValue();}
        return read;
    }

    public ArrayList <String> getScDNA(int s, int e, double t) {
        int sub = e - s;
        ArrayList <String>  prs = new ArrayList <String>();
        boolean repeat = true;int lBand=0;
        while(repeat && lBand < this.getSize()){if(this.getRead(lBand++).getEnd() >= s){repeat = false;}}
        repeat = true;int uBand=lBand;
        while(repeat && uBand < this.getSize()){if(this.getRead(uBand++).getStart() >= e){repeat = false;}}
        int sCut,eCut;
        for(int r=lBand; r<uBand;r++){
            if(this.getRead(r).getStart() <= s && this.getRead(r).getEnd() >= e){
                sCut = s - this.getRead(r).getStart();
                eCut = sCut + sub;
                prs.add(new String(this.getScDNA(r, t).substring(sCut, eCut)));
            }
        }
        return prs;
    }

    public void save(String fname){
        try{
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fname, false));
            oos.writeObject(this);
            oos.close();
        }
        catch(Exception e){}
    }

    public static PB load(String path) throws Exception{
        FileInputStream fis = null;
        try{fis = new FileInputStream(new File(path));}
        catch(FileNotFoundException nfne){}
        ObjectInputStream ois = new ObjectInputStream(fis);
        return (PB)ois.readObject();
    }

    public int getMisQs(int r, int tSite){
        if(prl.get(r).getStart() <= tSite && prl.get(r).getEnd() >= tSite && prl.get(r).getPols().size() > 0){
            for (int x = 0; x < prl.get(r).getPols().size(); x++) {
                if (prl.get(r).getPols().get(x).getTLoc() == tSite) {if (prl.get(r).getPols().get(x).isMis()) {return prl.get(r).getPols().get(x).getQASCII();}}
            }
        }
        return -1;
    }

    public void setReads(ArrayList <PR> prl){this.prl = prl;}
    public void setMaxQ(int q){maxQ = q;}
    public int getMaxQ(){return maxQ;}
    public PR getRead(int n){return prl.get(n);}
    public int getSize(){return prl.size();}
    public void add(PR read){prl.add(read);}
    public Seq getRef(){return ref;}
    public int getStart(int n){return prl.get(n).getStart();}
    public int getEnd(int n){return prl.get(n).getEnd();}
    public void setQDist(int [] qDist){this.qDist = qDist;}
}